#include "tunnel_func.h"
#define ADDRESS "127.0.0.1"
#define PORT 1080

#define SERVER_ADDRESS "127.0.0.1"
#define SERVER_PORT 8080


int main(int argc, char* argv[])
{
        //defaults
        bool debug = false;
        string addr = ADDRESS;
        int port = PORT;     
        
        string saddr = SERVER_ADDRESS;
        int sport = SERVER_PORT;     
		bool haveAddr = false;
        
        //argument parsing
        for(int i=1;i<argc;i++)         
        {
          string s = argv[i];
          if(s=="stop")
          {         
            stop(extractFname(argv[0]));
            return 0;
          }
          
          if(s=="--debug")
          {
            debug = true;
          }
          
          if(s=="--address")
          {
            if(++i>=argc)
            {
              printf("Bad parameters.");
              return 2;
            }
			saddr = argv[i];
          }

          if(s=="--domain")
          {
            if(++i>=argc)
            {
              printf("Bad parameters.");
              return 2;
            }
			saddr = getAddrFromDomainName(argv[i]);
          }
          
          if(s=="--port")
          {
            if(++i>=argc)
            {
              printf("Bad parameters.");
              return 2;
            }
            stringstream ss(argv[i]);
            ss >> sport;
          }
          
          if(s=="--laddress")
          {
            if(++i>=argc)
            {
              printf("Bad parameters.");
              return 2;
            }
            addr = argv[i];
          }
          
          if(s=="--lport")
          {
            if(++i>=argc)
            {
              printf("Bad parameters.");
              return 2;
            }
            stringstream ss(argv[i]);
            ss >> port;
          }
        }
        
        //daemonisation
        if(!debug)
        {
          if(daemon(1,0)<0)
          {
            perror("Chyba pri daemon.");
          }
        }
        
        //creating socket
        int sck, sock;  
        sockaddr_in address;
        sockaddr address2;                      
        socklen_t addr2_size = sizeof(address2);                
        sck = socket(PF_INET,SOCK_STREAM,0);    
        if(sck<0)
        {
          perror("Nepodarilo sa vytvorit socket!");
          return 1;
        }       
        
        //Prevent "Address already in use" message
        int tr=1;       
        if(setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int))<0 && debug)
        {
            perror("Chyba pri setsockopt");
        }
                
        //Binding socket
		bool gotAddr;
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = inet_addr(addr.c_str());
        address.sin_port = htons(port); 
        if(bind(sck,(sockaddr*)&address,sizeof(address))<0)
        {
            close(sck);
            perror("Neuspesny bind.");
            return 1;   
        }
        
        //set listen mode
        if(listen(sck,10)<0)
        {
          close(sck);
          perror("Neuspesny listen.");
          return 1;
        }

        if(debug){
          printf("Host: %s\nPort: %d\n", ADDRESS, PORT);
        }
        
        //Handle SIGCHLD signal
        signal(SIGCHLD,childdied);
        
        //Accept connection
        while((sock = accept(sck,&address2,&addr2_size))>=0)
        {
          //create child
          int pid = fork();
          if (pid<0)
          {
            perror("Chyba pri fork");
            break;
          }
          //parent stays in listen mode
          if(pid > 0) 
          {
            close(sock);
            continue;
          }       
          //child processes the request
          close(sck);          
          
          
          sockaddr_in tunnelServer;
          int outSock = socket(AF_INET, SOCK_STREAM, 0);  
          
           
          tunnelServer.sin_family = AF_INET;
          tunnelServer.sin_addr.s_addr = inet_addr(saddr.c_str());
          tunnelServer.sin_port = htons(sport); 
          
          //connect
          if(connect(outSock,(sockaddr *)&tunnelServer,sizeof(tunnelServer))!=-1)
          {
            cout << "Connected" << endl;            
            exchangeData(sock,outSock);            
          }
          else
          {            
            perror("Neuspecny connect");
            shutdown(sock, SHUT_RDWR);
            close(sock);
            close(outSock);
            exit(1); // FIXME exit code    
          }
          
          break;
        }       
        
        if(sock!=-1)
        {          
          char buf[BUF_SZ];       
          shutdown(sock,SHUT_WR);       
          while(read(sock,buf,sizeof(buf))>0); // naco je dobry takyto riadok?
          close(sock);
          if(debug)
          puts("Done");
        }
        else
        {
            perror("Chyba pri accept");
            return 1;    
        }
        
        return 0;
}
